/*************************************************************************
 * Copyright 2008 David Almilli
 *  
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 *  
 *     http://www.apache.org/licenses/LICENSE-2.0 
 *      
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 **************************************************************************/
package com.almilli.catnip.server;

import com.almilli.catnip.beacon.TiVoBeacon;
import com.almilli.catnip.logging.Log;
import com.almilli.catnip.logging.LogFactory;
import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;
import org.apache.catalina.deploy.ContextResourceLink;
import org.apache.tomcat.util.digester.CallMethodRule;
import org.apache.tomcat.util.digester.Digester;
import org.apache.tomcat.util.digester.Rule;
import org.apache.tomcat.util.digester.RuleSetBase;
import org.xml.sax.Attributes;

/**
 * The <code>HmeRuleSet</code> class is a RuleSet that knows how to parse hme.xml files for a
 * web application context
 * @author s2kdave
 */
public class HmeRuleSet extends RuleSetBase {
	private static final Log log = LogFactory.getLog(HmeRuleSet.class);

	@Override
	public void addRuleInstances(Digester digester) {

        digester.addRule("hme-app", new CreateResourcesRule());

        digester.addRule("hme-app/hme", new HmeAppCreateRule());
//        digester.addSetNext("hme-app/hme",
//                            "addChild",
//                            "org.apache.catalina.Container");
        
        digester.addCallMethod("hme-app/hme/hme-path", "setName", 0);
        
        digester.addRule("hme-app/hme/hme-path", 
        		new PathRule("addInitParameter", "Path"));
        
        digester.addRule("hme-app/hme/hme-class", 
        		new KeyValueRule("addInitParameter", "ApplicationClass"));
        
        digester.addRule("hme-app/hme/factory-class", 
        		new KeyValueRule("addInitParameter", "FactoryClass"));
        
        digester.addRule("hme-app/hme/hme-params", 
        		new KeyValueRule("addInitParameter", "ArgumentList"));
	}

	protected static class CreateResourcesRule extends Rule {
		
		private String beaconName;

	    @Override
	    public void begin(String namespace, String name, Attributes attributes)
	        throws Exception {
	        Context context =
	            (Context)digester.peek(digester.getCount() - 1);
	        
	        if (beaconName == null) {
	        	beaconName = ContextUtils.getTiVoBeaconName(context);
	        }
			
			//add a resource link for the tivo beacon
	        if (beaconName != null) {
	        	if (log.isDebugEnabled()) {
	        		log.debug("TiVoBeacon found under name: " + beaconName);
	        	}
				ContextResourceLink link = new ContextResourceLink();
				link.setName("TiVoBeacon");
				link.setGlobal(beaconName);
				link.setType(TiVoBeacon.class.getName());
				context.getNamingResources().addResourceLink(link);
	        } else {
	        	if (log.isDebugEnabled()) {
	        		log.debug("TiVoBeacon not found.");
	        	}
	        }
	    }

	}

	protected static class HmeAppCreateRule extends Rule {

	    @Override
	    public void begin(String namespace, String name, Attributes attributes)
	        throws Exception {
	        Context context =
	            (Context) digester.peek(digester.getCount() - 1);
	        Wrapper wrapper = context.createWrapper();
	        wrapper.setServletClass("com.almilli.catnip.web.HmeServlet");
	        wrapper.setLoadOnStartup(1);
			
	        digester.push(wrapper);
	        if (log.isDebugEnabled()) {
	        	log.debug("new " + wrapper.getClass().getName());
	        }
	    }

	    @Override
	    public void end(String namespace, String name)
	        throws Exception {
	        Context context =
	            (Context) digester.peek(digester.getCount() - 1);
	        Wrapper wrapper = (Wrapper) digester.pop();
			context.addChild(wrapper);
	        
	        //add a servlet mapping for the hme app
	        String path = wrapper.getName();
	        if (path != null && !path.endsWith("/")) {
	        	path += "/";
	        }
			context.addServletMapping(path + "*", wrapper.getName());
	        if (log.isDebugEnabled()) {
	        	log.debug("pop " + wrapper.getClass().getName());
	        }
	    }

	}
	
	protected static class KeyValueRule extends CallMethodRule {
		protected Object key;
		protected String value;

		public KeyValueRule(String methodName, Object key) {
			super(methodName, 2);
			this.key = key;
		}

		@Override
		public void begin(String namespace, String name, Attributes attributes)
	        throws Exception {
	    	super.begin(namespace, name, attributes);

            Object[] params = (Object[]) digester.peekParams();
            params[0] = key;
	    }

		@Override
		public void body(String bodyText) throws Exception {
			super.body(bodyText);
			value = bodyText.trim();
		}

		@Override
		public void end() throws Exception {
            Object[] params = (Object[]) digester.peekParams();
            params[1] = value;
			super.end();
		}
	}

	protected static class PathRule extends KeyValueRule {
		public PathRule(String methodName, Object key) {
			super(methodName, key);
		}

		@Override
		public void body(String bodyText) throws Exception {
			super.body(bodyText);
			if (!value.endsWith("/")) {
				value += "/";
			}
		}
	}
}
